/*
* 2018/03/30
* 任建华
* 抽奖脚本
* 方法解析：
*   初始化： 例： var myLottery = Lottery(options, rotateDom)
*       @params: options 必需 抽奖的项目
*           如果各项中奖概率平均 需要传一个数组 每一项为参与抽奖的一项 如：['1000元', '50元', '5元', '谢谢参与', '第二个5元']（按转盘零度角逆时针顺序传入）
*           如果需要设置具体某一项的中奖概率 需要传一个对象 如：{'1000元': 1, '50元': 0, '5元': 0, '谢谢参与': 0, '第二个5元': 0} 各项概率和如果不足1 剩余的概率会加到最后一个属性上 大于1会降低最后一项的中奖概率
*           注： 每一项属性名不可重复
*       @params: rotateDom 可选 转动的对象 如果不传默认是id为'rotate-img'的节点
*
*   开始抽奖: 调用实例对象的rotate方法 例：myLottery.rotate(callback)
*       @params: callback 可选 转动结束后的回调函数 可用于弹窗等操作
*
*   重置角度：调用实例对象的resetDeg方法 例：myLottery.resetDeg()
*       默认在每次抽奖结束后转盘会保持上一次的角度 如需要重置为0 调用resetDeg()方法
*
*   重置参数：调用实例对象的resetParams方法 例：myLottery.resetParams(options)
*       如果需要改变中奖概率可以调用此方法
*       @params: options 和初始化的参数options一致
* */

(function (window) {

    function Lottery(options, rotateDom) {
        return Lottery.prototype.init(options, rotateDom)
    }

    Lottery.fn = Lottery.prototype = {

        constructor: Lottery,

        init: function (options, rotateDom) {

            if (!options || (this.getType(options) != 'array' && this.getType(options) != 'object')) return

            this.options = options
            this.lotteryData = {}                                         // 抽奖集合
            this.result = ''                                              // 中奖项
            this.currentDeg = 0                                           // 本次抽奖转动的角度
            this.lastDeg = 0                                              // 上一次抽奖转动的角度
            this.stop = true                                              // flag 标记抽奖是否应该结束
            this.step = 0                                                 // 速度 每一帧转动的角度
            this.a = 0                                                    // 加速度
            this.reduceA = 0                                              // 减速部分的随机加速度
            this.rotateDom = rotateDom || document.querySelector('#rotate-img') // 转动的节点
            this.itemArr = []                                             // 抽奖项的数组
            this.resultIndex = -1                                         // 中奖项的索引
            this.targetDeg = 0                                            // 随机中奖项的角度

            // 初始化抽奖项目
            this.resetParams(this.options)

            return this
        },

        resetParams: function (options) {

            if (!options) return

            this.options = options
            this.computeProbability(options)
        },

        resetDeg: function (callback) {

            this.lastDeg = (this.lastDeg % 360)
            this.lastDeg += 3

            if (this.lastDeg > 359) {

                this.lastDeg = 0
                this.rotateDom.style.transform = 'rotate(0deg)'

                callback && this.getType(callback) === 'function' && callback()

                return
            }

            this.rotateDom.style.transform = 'rotate(' + this.lastDeg + 'deg)'

            window.requestAnimationFrame(() => {
                this.resetDeg()
            })
        },

        getType: function (obj) {

            if (!obj) return ''

            if (typeof obj !== 'object') return typeof obj

            if (typeof obj === 'function') return 'function'

            return Array.isArray(obj) ? 'array' : 'object'
        },

        computeProbability: function (target) {

            var len, k, sum = 0;

            if (this.getType(target) === 'array') {
                len = target.length

                target.forEach((v) => {
                    this.lotteryData[v] = 1 / len
                })

            } else if (this.getType(target) === 'object') {
                this.lotteryData = target
            }

            this.itemArr = []

            for (k in this.lotteryData) {
                this.itemArr.push(k)
                sum += this.lotteryData[k]
                this.lotteryData[this.itemArr.length - 1] = [sum - this.lotteryData[k], sum]
                delete this.lotteryData[k]
            }

            return this
        },

        getResult: function () {

            var randomNum, k;

            randomNum = Math.random()

            for (k in this.lotteryData) {

                this.result = this.itemArr[k - 0]
                this.resultIndex = k - 0

                if (this.lotteryData[k][0] <= randomNum && randomNum < this.lotteryData[k][1]) break

            }

            this.targetDeg = this.getTargetDeg()

            return this
        },

        rotate: function (callback) {

            if (!this.stop) return

            this.stop = false

            // 初始化属性 => 随机出结果 => 转盘渲染结果
            this.initLottery().getResult().render(callback)
        },

        initLottery: function () {

            if (this.lastDeg != 0) {

                this.lastDeg = (this.lastDeg / 360) > 50 ? this.lastDeg % 360 : this.lastDeg

                this.rotateDom.style.transform = 'rotate(' + this.lastDeg + 'deg)'
            }

            this.step = 0
            this.a = 0
            this.currentDeg = 0
            this.reduceA = (Math.floor(Math.random() * 30) + 40) * -0.001

            return this
        },

        render: function (callback) {

            this.stop = false

            this.setSpeed()

            this.step += this.a
            this.currentDeg += this.step
            this.rotateDom.style.transform = 'rotate(' + (this.currentDeg + this.lastDeg) + 'deg)'

            this.isStop(callback)

            if (this.stop) return

            window.requestAnimationFrame(() => {
                this.render(callback)
            })
        },

        setSpeed: function () {

            if (this.currentDeg < 720) return this.a += 0.001

            if (720 <= this.currentDeg && this.currentDeg < 2160) return this.a = 0

            if (2160 <= this.currentDeg) return this.a = this.reduceA
        },

        isStop: function (callback) {
            var num;

            if (this.currentDeg <= 2160) return this.stop = false

            if (this.step <= 2) {

                this.step = 2
                this.a = 0

                num = (this.currentDeg + this.lastDeg) % 360

                if (Math.abs(num - this.targetDeg) < 1) {

                    // 转盘停止
                    this.stop = true
                    this.lastDeg += this.currentDeg

                    // 如果参数存在并且参数是一个回调函数就执行此回调
                    callback && this.getType(callback) === 'function' && callback()
                }
            }
        },

        getTargetDeg: function () {

            var num, itemDeg, target;

            itemDeg = 360 / this.itemArr.length
            num = Math.floor(Math.random() * (itemDeg - 20))
            target = (this.resultIndex - 0.5) * itemDeg + 10 + num

            // 如果随机得到负数 + 360
            target = Math.sign(target) === -1 ? target + 360 : target

            return target
        }
    }

    Lottery.prototype.init.prototype = Lottery.prototype

    window.Lottery = Lottery
})(window)